#!/usr/bin/env perl
#
# slimrat - main GUI script
#
# Copyright (c) 2008-2009 Přemek Vyhnal
#
# This file is part of slimrat, an open-source Perl scripted
# command line and GUI utility for downloading files from
# several download providers.
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# Authors:
#    Přemek Vyhnal <premysl.vyhnal gmail com>
#    Tim Besard <tim-dot-besard-at-gmail-dot-com>
#



#################
# CONFIGURATION #
#################

#
# Dependancies
#

# Packages
use Gtk2 -init;
use Gtk2::GladeXML;
use Glib qw(TRUE FALSE);
use Gtk2::SimpleList;
use File::Basename;

# Find root for custom packages
use FindBin qw($RealBin);
use lib $RealBin;

# Custom packages
use Log;
use Clipboard;
use Plugin;
use Toolbox;
use Configuration;

# Write nicely
use warnings;
use strict;


#
# Essential stuff
#

# Register signals
$SIG{'INT'} = 'quit';

# Initialise configuration handler and configure default values
my $config = new Configuration;
$config->add_default("terminal", 'xterm -T SlimRat -e "%1$s; bash"&');
$config->add_default("queue_file",  $ENV{HOME}.'/.slimrat/queue');
$config->add_default("glade_file",  $RealBin.'/slimrat.glade');

# Read configuration files (this section should contain the _only_ hard coded paths, except for default values)
if (-r "/etc/slimrat.conf") {
	$config->file_read("/etc/slimrat.conf");
}
if (-r $ENV{HOME}."/.slimrat/config") {
	$config->file_read($ENV{HOME}."/.slimrat/config");
}

# Make sure slimrat has a proper directory in the users home folder
if (! -d $ENV{HOME}."/.slimrat") {
	debug("creating a directory in the home folder");
	unless (mkdir $ENV{HOME}."/.slimrat") {
		fatal("could not create slimrat's home directory");
	}
}

# Global variables
my $ctrl;

# Keypresses
use constant KEY_CTRL	=> 65507;
use constant KEY_v	=> 118;
use constant KEY_V	=> 86;
use constant KEY_DELETE	=> 65535;
use constant KEY_INSERT	=> 65379;
use constant KEY_ENTER	=> 65293;

# Construct the GUI
my $gui = Gtk2::GladeXML->new($config->get("glade_file"), 'mainWindow');
$gui->signal_autoconnect_from_package('main');

# Treeview
use constant {
	COL_STATUS	=> 0,
	COL_PASS	=> 3,
	COL_TYPE	=> 1,
	COL_LINK	=> 2,
};

# Configure the listview
my $slist = Gtk2::SimpleList->new(
	''		=> 'pixbuf',
	'Type'		=> 'text',
	'Link'		=> 'text',
	'Pass'		=> 'text',
);
$slist->get_column(COL_PASS)->set_visible(0);
$slist->get_selection->set_mode ('multiple');
$slist->get_column($_)->set_resizable(1) foreach (COL_STATUS, COL_TYPE, COL_LINK, COL_PASS);
$slist->get_column($_)->set_reorderable(1) foreach (COL_STATUS, COL_TYPE, COL_LINK, COL_PASS);
$slist->set_column_editable ($_, TRUE) foreach (COL_LINK, COL_PASS);
$slist->set_search_column(COL_LINK);
$slist->set_search_equal_func(sub { # search (as-you-type) links in the list not only at the beginning of the string but also in the middle of the string
	my($store,$col,$pat,$iter)=@_;
	return $store->get($iter,$col) !~ m/\Q$pat\E/i;
});
$gui->get_widget('mainwin')->add_with_viewport($slist);
$gui->get_widget('mainwin')->show_all;

# Statusbar
# TODO
#$gui->get_widget('statusbar')->push(0,"AAAA");

# Load queue'd URLs
# TODO: move to the Queue structure, we'll need a save_queue (selective dump + filename save) to support this
open(QUEUE, "+<" . $config->get("queue_file"));
while (<QUEUE>){
	chomp;
	my @newRow;
	$newRow[COL_STATUS] = $slist->render_icon ("gtk-dialog-question", 'menu');
	$newRow[COL_TYPE] = Plugin::get_name($_);
	$newRow[COL_LINK] = $_;
	push @{$slist->{data}},[@newRow];
}
close(QUEUE);

# Activate the GUI
Gtk2->main;



############
# ROUTINES #
############

#
# Essential stuff
#

# Window got destroyed 
sub on_mainWindow_destroy { &quit; }

# Quit the application
sub quit {
	&saveque;
	Gtk2->main_quit;
}

# Save the queue
sub saveque {
	open(QUEUE, "> " . $config->get("queue_file"));
	print QUEUE @{$_}[COL_LINK]."\n" foreach @{$slist->{data}};
	close(QUEUE);
}

# parse links from text input or clipboard and add them
sub links_parse_add {
	my $links = shift;
	push @{$slist->{data}}, [ $slist->render_icon ("gtk-dialog-question", 'menu'), Plugin::get_name($_), $_] foreach split /\n+/, $links; # TODO mezery na začátku;

}

# Moving treeview items
sub move_item {
	my($from,$to) = @_;
	return if($to<0 || $to >= scalar @{$slist->{data}});
	splice @{$slist->{data}}, $to, 0, splice @{$slist->{data}}, $from, 1; 
	$slist->unselect($from);
	$slist->select($to);
}

# Select all
sub select_all {
	$slist->select($_) foreach (0 .. (scalar @{$slist->{data}})-1);
}


#
# Key handling
#

# Keypress handler
sub key_press {
	my ($cmdbox, $event)=@_;
	if($event->keyval==KEY_CTRL){$ctrl = 1;}
	elsif($ctrl && ($event->keyval==KEY_v || $event->keyval==KEY_V)){&on_btnAddClip_clicked;}
	elsif($event->keyval==KEY_DELETE){&on_btnRemove1_clicked;}
	elsif($event->keyval==KEY_INSERT){&on_btnAdd1_clicked;}
}

# Keyrelease handler
sub key_release {
	my ($cmdbox, $event)=@_;
	if($event->keyval==KEY_CTRL) {$ctrl = 0;}
}

# Keypress handler within a dialog
sub on_addDialog_key_press_event {
	my ($cmdbox, $event)=@_;
	if($event->keyval==KEY_CTRL){$ctrl = 1;}
	&on_addOkBtn_clicked if($ctrl && $event->keyval==KEY_ENTER);
}

# Keyrelease handler within a dialog
sub on_addDialog_key_release_event {goto &key_release;}


#
# Toolbar
#

# Start download
sub on_btnStart1_clicked {
	&saveque; 
	my $download_to = $gui->get_widget('downto')->get_filename();
	my $unpack = "";
	if($gui->get_widget('unpack')->get_active()) { # unpack
		$unpack = "-u";
		@{$_}[COL_PASS] and $unpack.=" -p ".@{$_}[COL_PASS] foreach @{$slist->{data}};
	}
	my $command = sprintf $config->get("terminal"), "$RealBin/slimrat -l '".$config->get("queue_file"). "' -t '$download_to' $unpack";
	system($command);
	&quit;
}

# Check selected URLs
# if no link selected, check all
# DEAD links will remain SELECTED (do we want this? or do we want to keep the selection?)
sub on_btnCheck_clicked {
	select_all() if(scalar $slist->get_selected_indices == 0);
	foreach my $rownum ($slist->get_selected_indices){
		my $row = @{$slist->{data}}[$rownum];
		my $link = @{$row}[COL_LINK];
		my $pluginname = Plugin::get_name($link);
		my $check = eval $pluginname."::check('$link')";
		my $ico;
		if($check>0) { #live
			$ico="gtk-yes";
			$slist->unselect($rownum);
		} elsif($check<0) { # dead
			$ico="gtk-no";
			$slist->select($rownum);
		} else { #?
			$ico="gtk-dialog-question";
			$slist->unselect($rownum);
		}
		$row->[COL_STATUS] = $slist->render_icon ($ico, 'menu');
		$rownum++;
	}
}

# Add from clipboard
sub on_btnAddClip_clicked {
	links_parse_add(Clipboard->paste);
}

# Add
my ($addDialog, $addDialogBuff);
sub on_btnAdd1_clicked {
	my $gui = Gtk2::GladeXML->new($config->get("glade_file"), 'addDialog');
	$gui->signal_autoconnect_from_package('main');
	$addDialog = $gui->get_widget('addDialog');
	$addDialogBuff = $gui->get_widget('addLinks')->get_buffer();
}

# Remove
my $confirmDialog;
sub on_btnRemove1_clicked{
	if(scalar $slist->get_selected_indices > 0){
		# Confirm dialog
		my $gui = Gtk2::GladeXML->new($config->get("glade_file"), 'confirmDelete');
		$gui->signal_autoconnect_from_package('main');
		$confirmDialog = $gui->get_widget('confirmDelete');
	}
}

# Remove all
sub on_btnRemoveAll_clicked{
	select_all();
	&on_btnRemove1_clicked;
}

# Move to top
sub on_btnBeg1_clicked{
	my $i=0;
	move_item($_,$i++) foreach ($slist->get_selected_indices);
}

# Move up
sub on_btnUp1_clicked{
	return if (grep($_-1<0,$slist->get_selected_indices));
	move_item($_, $_-1) foreach ($slist->get_selected_indices);
}

# Move down
sub on_btnDown1_clicked{
	return if (grep($_+1>=scalar @{$slist->{data}},$slist->get_selected_indices));
	move_item($_,$_+1) foreach (reverse $slist->get_selected_indices);
}

# Move to bottom
sub on_btnEnd1_clicked{
	my $i=scalar @{$slist->{data}}-1;
	move_item($_,$i--) foreach (reverse $slist->get_selected_indices);
}

# Quit
sub gtk_main_quit { &quit; }


#
# Add dialog
#

# Add dialog cancel button
sub on_addCancelBtn_clicked {
	$addDialog->destroy();	
}

# Add dialog OK button
sub on_addOkBtn_clicked {
	links_parse_add($addDialogBuff->get_text($addDialogBuff->get_start_iter, $addDialogBuff->get_end_iter, FALSE));
	$addDialog->destroy();	
}

# Confirm dialog
sub on_confirmDelete_response{
#if($_[1] eq 'no' || $_[1]=='delete-event'){
	if($_[1] eq 'yes'){
		my $i=0;
		splice (@{$slist->{data}}, $_- $i++, 1) foreach ($slist->get_selected_indices);
	}
	$confirmDialog->destroy();
}

# Unpack dialog - show/hide pass col
sub on_unpack_toggled {
	$slist->get_column(COL_PASS)->set_visible($gui->get_widget('unpack')->get_active());
}

